#pragma once

#include <stdint.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <unistd.h>
#include <arpa/inet.h>
#include "user.hpp"
#include <mutex>
#include <thread>         
#include <vector>         
#include <iostream>

// 单个线程执行的task/用户
void serverTask(int tcpSock, std::mutex& _mutexThread, std::map<std::string, USER::userMsg>& _userMap) // 注：由于每个线程会访问共享资源（线程安全），所以要传锁
{
    //获取用户IP
    USER::userMsg actUser;
    ssize_t lenIP = recv(tcpSock, (void*)&actUser, sizeof(actUser), 0);
    if (lenIP < 0) 
    {
        std::cerr << "Failed to receive struct." << std::endl;
        exit(-1);
    }
    //填写用户信息
    actUser._state = USER::ONLINE;
    actUser._sock = tcpSock;
    //用户上线 -> 检验用户是否为新用户（这里可以接入数据库）

    auto userPtr = _userMap.find(actUser._IP);
    if (userPtr == _userMap.end())
    {
        
        //新用户 -> 将新用户形象放入管理表中
        _mutexThread.lock();
        //insert返回值是一个pair
        //第一个元素是一个迭代器，指向插入的元素（或者如果元素已经存在，则指向现有元素）
        //第二个元素是一个布尔值，指示插入是否成功。
        userPtr = _userMap.insert(std::make_pair(actUser._IP, actUser)).first;  
        _mutexThread.unlock();    
    }
// std::cout << "mapSize: "<< _userMap.size() <<std::endl;
// std::cout << "map1: "<< _userMap.begin()->first <<std::endl;


    (*userPtr).second._state = USER::ONLINE;
//std::cout<<"1"<<std::endl;
    //开始服务该客户端
    char buffer[1024];
    while (true)
    {
        // 读取客户端发送的信息

        ssize_t n = recv(actUser._sock, (void*)&buffer, sizeof(buffer), 0);

        if (n > 0)
        {
            // 目前我们把读到的数据当成字符串, 截止目前
            buffer[n] = 0;
            std::cout << "server view: " << buffer << std::endl; // 以服务器中间人的视角，观察客户端间的交流
            // for(auto &e:_userMap)
            // {
            //     std::cout<<e.first<<std::endl;
            // }
            
            for (auto e =_userMap.begin();e != _userMap.end();e++)
            {
                if ((*e).first != actUser._IP && (*e).second._state == USER::ONLINE) // 除了自己都发,且在线用户
                {
                    std::cout<<"转发"<<std::endl;
                    //write(e.second._sock, buffer, sizeof(buffer));
                    send((*e).second._sock, buffer, sizeof(buffer),0);
                    std::cout<<"转发成功"<<std::endl;
                }
                   
            }

            
        }
        else if(n <= 0)
        {
            // 用户下线将其状态置为下线
            std::cout << actUser._IP << ":用户下线"<< std::endl;
            _mutexThread.lock();
            (*userPtr).second._state = USER::OFFLINE;
            _mutexThread.unlock();
            break;
        }
    }
    //修改套接字
    close(actUser._sock);
    _userMap[actUser._IP]._sock = -1;
}

namespace server
{
    class tcpServer
    {
    private:
        int _listenSock;
        uint16_t _port;
        std::map<std::string, USER::userMsg> _user;  // 被所有线程都使用 -》注意线程安全
        std::vector<std::unique_ptr<std::thread>> _threads;//由于thread类的构造函数被删除 -》 存它的指针才行！！！
        // std::vector<std::thread>_threads;
        std::mutex _mutexThread;                // 用于解决各线程的线程安全

    public:
        tcpServer(const uint16_t &port) : _listenSock(-1), _port(port)
        {}

        // tcp通信前需要设置监听套接字
        void initServe()
        {
            // 1.创建套接字
            _listenSock = socket(AF_INET, SOCK_STREAM, 0);
            // 2.绑定（bind）套接字与网络信息
            struct sockaddr_in local;
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;

            if (bind(_listenSock, (sockaddr *)&local, sizeof(local)) < 0)
            {
                std::cout << "bind socket error" << std::endl;
                exit(-1);
            }

            // 3.将套接字设为监听状态
            if (listen(_listenSock, 5) < 0) 
            {
                std::cout << "listen socket error" << std::endl;
                exit(-1);
            }
        }

        void start()
        {

            while (true)
            {
                sockaddr_in peer; // 用于记录客户端的网络信息
                socklen_t peerLen = sizeof(peer);

                int tcpSock = accept(_listenSock, (sockaddr *)&peer, &peerLen);
                if (tcpSock < 0)
                {
                    std::cout << "accept error, next" << std::endl;
                    continue;
                }

                // 到这里说明有客户端连接成功           

                // 服务端用于观察客户端间的交流内容(可用于调试观察) -> 打印当前新接入的的客户端ip：对应的本地的sock
                char clientMes[INET_ADDRSTRLEN];
                std::string clientIP = inet_ntop(peer.sin_family, &peer.sin_addr.s_addr, clientMes, INET_ADDRSTRLEN);
                std::cout << clientIP << ":" << peer.sin_port <<"用户上线"<< std::endl;

                //给客户端提供服务的任务（线程）
                //std::thread tmp(serverTask,tcpSock,_mutexThread,_user);
                //std::unique_ptr<std::thread> tmp(new std::thread(serverTask, tcpSock, _mutexThread, _user));

                std::unique_ptr<std::thread> tmp(new std::thread(serverTask, tcpSock, std::ref(_mutexThread), std::ref(_user)));

                tmp->detach();//线程分离 -》主线程不用join等待，而导致变成串行执行
                _threads.push_back(std::move(tmp)); //移动构造
                             
            }
        }
    };
    

};
